using System.Security.Cryptography;
using System.Text.RegularExpressions;
using UniversalAdminSystem.Application.UserManagement.Interface;

namespace UniversalAdminSystem.Infrastructure.Services;

public class PasswordHelper : IPasswordHelper
{
    private const int SaltSize = 16;
    private const int HashSize = 32;
    private const int Iterations = 1000;

    /// <summary>
    /// 密码加密
    /// </summary>
    /// <param name="password"></param>
    /// <returns></returns>
    public (string hashedPassword, string salt) HashPasswordWithSeparateSalt(string password)
    {
        if (!Regex.IsMatch(password, "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z][^\u4e00-\u9fa5]{5,19}$", RegexOptions.IgnoreCase)) throw new ArgumentException("密码必须是数字+字母组合并且不含中文 长度6至20位");
        byte[] salt = new byte[SaltSize];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(salt);
        }

        using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, Iterations, HashAlgorithmName.SHA256))
        {
            byte[] hash = pbkdf2.GetBytes(HashSize);
            return (hashedPassword: Convert.ToBase64String(hash),
            salt: Convert.ToBase64String(salt));
        }

    }
    /// <summary>
    /// 密码比对
    /// </summary>
    /// <param name="password"></param>
    /// <param name="storedHashedPassword"></param>
    /// <param name="storedSalt"></param>
    /// <returns></returns>
    public bool VerifyPasswordWithSeparateSalt(string password, string storedHashedPassword, string storedSalt)
    {
        byte[] storedHash = Convert.FromBase64String(storedHashedPassword);
        byte[] salt = Convert.FromBase64String(storedSalt);

        using (var pbkdf2 = new Rfc2898DeriveBytes(
            password,
            salt,
            Iterations,
            HashAlgorithmName.SHA256))
        {
            byte[] computedHash = pbkdf2.GetBytes(HashSize);

            // 安全比较
            return CryptographicOperations.FixedTimeEquals(
                storedHash.AsSpan(),
                computedHash.AsSpan());
        }
    }
    
}